#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PHMEE.Entities.BaseInfo.Units;
using PHMEE.PHM.Algorithms.Diagnosis;
using Volo.Abp.Domain.Services;

namespace PHMEE.Managers.Diagnosis;

/// <summary>
/// 空气压缩机故障诊断
/// </summary>
public class AirCompressorFaultDiagnosisDomainService : DomainService, IAirCompressorFaultDiagnosisDomainService
{
    private readonly AirCompressorAlg _airCompressorAlg;
    private readonly IBearingParametersDomainService _bearingParametersDomainService;

    public AirCompressorFaultDiagnosisDomainService(
        AirCompressorAlg airCompressorAlg,
        IBearingParametersDomainService bearingParametersDomainService)
    {
        _airCompressorAlg = airCompressorAlg;
        _bearingParametersDomainService = bearingParametersDomainService;
    }

    /// <summary>
    /// 空气压缩机故障诊断
    /// </summary>
    /// <param name="pointPosition"></param>
    /// <param name="sampleRate"></param>
    /// <param name="unitWithEquips"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public async Task<string[]> FaultDiagnosisAsync(PointPosition pointPosition, float sampleRate,
        UnitWithEquipsDto unitWithEquips,
        float[] data)
    {
        // 设备参数和阈值初始化
        var equipmentParameters = new AirCompressorEquipmentParameters();
        var thresholds = new AirCompressorThresholds();

        // 验证并提取设备信息
        var (asynchronousElectricMotor, reciprocatingCompressor) =
            ValidateAndExtractUnitEquipments(unitWithEquips.UnitEquips);

        // 提取异步电动机参数
        ExtractAsynchronousElectricMotorParameters(asynchronousElectricMotor, equipmentParameters);

        // 提取轴承信息
        await ExtractBearingParametersAsync(asynchronousElectricMotor, reciprocatingCompressor, equipmentParameters);

        // 提取阈值
        ExtractThresholds(unitWithEquips.Unit, thresholds);

        // 调用空气压缩机故障诊断算法
        var response =
            await _airCompressorAlg.AirCompressorAsync(pointPosition, data, sampleRate, equipmentParameters,
                thresholds);

        return response.FaultCodes.ToArray();
    }

    private static (AsynElectricMotor, ReciprocatingCompressor) ValidateAndExtractUnitEquipments(
        List<Equipment> unitEquips)
    {
        if (unitEquips.Count == 0)
        {
            throw new InvalidOperationException(nameof(Equipment));
        }

        if ((unitEquips.FirstOrDefault(e => e.Type == EquipmentEnum.AsynElectricMotor)
             ?? throw new InvalidOperationException(nameof(EquipmentEnum.AsynElectricMotor)))
            is not AsynElectricMotor asynchronousElectricMotorEquip)
        {
            throw new InvalidOperationException(nameof(AsynElectricMotor));
        }

        asynchronousElectricMotorEquip.DeserializeProperties();

        if ((unitEquips.FirstOrDefault(e => e.Type == EquipmentEnum.ReciprocatingCompressor)
             ?? throw new InvalidOperationException(nameof(EquipmentEnum.ReciprocatingCompressor)))
            is not ReciprocatingCompressor reciprocatingCompressorEquip)
        {
            throw new InvalidOperationException(nameof(ReciprocatingCompressor));
        }

        reciprocatingCompressorEquip.DeserializeProperties();

        return (asynchronousElectricMotorEquip, reciprocatingCompressorEquip);
    }

    private static void ExtractAsynchronousElectricMotorParameters(AsynElectricMotor asynchronousElectricMotor,
        AirCompressorEquipmentParameters equipmentParameters)
    {
        equipmentParameters.Rpm = (float)asynchronousElectricMotor.MotorSpeed;
        equipmentParameters.Lf = (float)asynchronousElectricMotor.Frequency;
        equipmentParameters.Rbpf = (float)asynchronousElectricMotor.RotorBarsNumber;
        equipmentParameters.Power = (float)asynchronousElectricMotor.Power;
    }

    private async Task ExtractBearingParametersAsync(AsynElectricMotor asynchronousElectricMotor,
        ReciprocatingCompressor reciprocatingCompressor,
        AirCompressorEquipmentParameters equipmentParameters)
    {
        equipmentParameters.BearMotorDrive.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(asynchronousElectricMotor.DriveEndBearFactoryFirst, asynchronousElectricMotor.DriveEndBearModelFirst));
        equipmentParameters.BearMotorFree.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(asynchronousElectricMotor.NonDriveEndBearFactory, asynchronousElectricMotor.NonDriveEndBearModel));
        equipmentParameters.BearCompressorDrive.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(reciprocatingCompressor.DriveEndBearFactoryFirst, reciprocatingCompressor.DriveEndBearModelFirst));
        equipmentParameters.BearCompressorFree.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(reciprocatingCompressor.NonDriveEndBearFactory, reciprocatingCompressor.NonDriveEndBearModel));
    }

    /// <summary>
    /// 从 Unit 提取阈值
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    /// <exception cref="InvalidOperationException"></exception>
    private static void ExtractThresholds(Unit unit, AirCompressorThresholds thresholds)
    {
        if (unit is StartingAirCompressUnit airCompressUnit)
        {
            ExtractThresholdsForStartingAirCompress(airCompressUnit, thresholds);
        }
        else
        {
            throw new InvalidOperationException(nameof(Unit));
        }
    }

    /// <summary>
    /// 空气压缩机阈值提取
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    private static void ExtractThresholdsForStartingAirCompress(StartingAirCompressUnit unit, AirCompressorThresholds thresholds)
    {
        unit.DeserializeProperties();

        thresholds.Acc = (float)unit.Acc;
        thresholds.MRms.AddRange(new[] { (float)unit.MrmsA, (float)unit.MrmsB, (float)unit.MrmsC });
        thresholds.Value1X.AddRange(new[] { (float)unit.Value1XA, (float)unit.Value1XB });
        thresholds.Bear.AddRange(new[]
        {
            (float)unit.BearA,
            (float)unit.BearB,
            (float)unit.BearC,
            (float)unit.BearD,
            (float)unit.BearE1,
            (float)unit.BearE2,
            (float)unit.BearE3,
            (float)unit.BearE4,
            (float)unit.BearE5
        });
        thresholds.ArmatureFault.AddRange(new[] { (float)unit.ArmatureFaultA, (float)unit.ArmatureFaultB });
        thresholds.ResonanceFault = (float)unit.ResonanceFault;
        thresholds.StructureLoose = (float)unit.StructureLoose;
        thresholds.Misalignment.AddRange(new[] { (float)unit.MisalignmentA, (float)unit.MisalignmentB });
        thresholds.CRms.AddRange(new[] { (float)unit.CrmsA, (float)unit.CrmsB, (float)unit.CrmsC });
        thresholds.AxleWear1 = (float)unit.AxleWear1;
        thresholds.AxleWear2 = (float)unit.AxleWear2;
    }
}